#pragma once

#include "Containers/Containers.h"
#include "Reflection/FunctionID.h"
#include "Path/Path.h"


#include "ScriptRuntime/ByteCode/ByteCodeInstruction.h"
#include "ScriptRuntime/ScriptAccessLevel.h"

#include "ScriptRuntime/ScriptInnerType.h"

#include "ScriptRuntime/ByteCode/ByteCodeSectionTypes.h"
#include "ScriptRuntime/Type/ConstantValue.h"

class WHENGINE_API CByteCodeFile
{
public:

    // struct SHead
    // {
    //     uint32_t TypeNumer=-1;

    // }

    struct SSourceCodeFile
    {
        SPath FilePath;
        uint32_t LineCount=0;

    };

    struct STypeInfo
    {
        STypeID TypeID;

        //only valid for generic type
        TVector<STypeID> OverrideGenericTypes;

        uint32_t CountSize() const
        {
            return 4;
        }
    };

    struct SGeneralizedClasseInfo
    {
        STypeID TypeID;

        //only script class type has this
        STypeID RawClassTypeID ;

        TOptional<STypeID> BaseTypeID ;

        CString Name;

        STypeID TemplateID;

        TVector<STypeInfo> ArgumentInfos;

        // uint32_t CountSize() const
        // {
        //     return 4 /*ID*/ + 4 /*TemplateID*/
        //      + 4 /*Argument num*/ +  4 * ArgumentInfos.Num(); 
        // }
    };



    struct SGenericPlaceholderTypeInfo
    {
        STypeID TypeID;

        CString Name;

        uint32_t CountSize() const
        {
            return 4 /*ID*/ + 4 /*Name*/ ;
        }
    };

    struct SFunctionType
    {
        STypeID TypeID;
        
        CString Name;

        STypeInfo ReturnType;

        TVector<STypeInfo> ParameterTypes;

        uint32_t CountSize() const
        {
            return 4 /*ID*/ + 4 /*ReturnType*/
             + 4 /*Parameter num*/ +  4 * ParameterTypes.Num(); 
        }
    };

    struct SClassInfo
    {
        EScriptAccessLevel AccessLevel;

        bool IsAbstract=false;
        bool bIsInnerType=false;
        bool bIsStruct=false;
        bool bIsEnum=false;
        bool bIsDelegate=false;



        TVector<CString> NameScopeID;

        CString Name;
        STypeID TypeID;
        
        STypeID BaseTypeID ;

        //only script class type has this
        STypeID RawClassTypeID ;

        TVector<SGenericPlaceholderTypeInfo> GenericPlaceholders;

        //only valid for enum
        TVector<CString> EnumNames;
        TVector<int64_t> EnumValues;

        //only valid for delegate
        STypeID DelegateFunctionType;
    };


    struct SMemberDecorator
    {

        bool bIsConst=false;
        bool bIsStatic=false;
    
        uint32_t CountSize() const
        {
            return 1;
        }
    };

    struct SFieldInfo
    {
        EScriptAccessLevel AccessLevel;
        SMemberDecorator Decorator;
        STypeInfo Type;
        CString Name;
        uint32_t FieldIndex=-1;
        bool bIsStatic=false;

        TOptional<CConstantValue> DefaultValue; //only valid for static field

    };
    
    struct SBreakpointInfo
    {
        uint32_t FileIndex=0;
        uint32_t SourceCodeLineNumber=0;
        uint32_t InstructionIndex=0;
    };

    struct SVariableInfo
    {
        STypeInfo Type;
        CString Name;
    };


    struct SFunctionInfo
    {
        EScriptAccessLevel AccessLevel;
        //decorators
        bool bIsStatic=false;
        
        STypeInfo ReturnType;
        CString Name;

        // TVector<CString> ParameterNames;
        // TVector<STypeInfo> ParameterTypes;
        TVector<SVariableInfo> Parameters;

        //TVector<STypeInfo> VariableStack;
        TVector<SVariableInfo> VariableStack;

        //instruction position relative to first instruction, so first instruction position is 0
        TVector<uint32_t> LinePositions;

        TVector<SBreakpointInfo> BreakablePoints;

        bool IsStatic() const
        {
            return bIsStatic;
        }
    };

    struct SFunctionCallInfo
    {
        STypeID Class;

        uint32_t Function = -1;  //index of function in the class, for virtual function, it is the index in virtual table

        // uint32_t CountSize() const
        // {
        //     return  Class.CountSize() + 4  /* Function index */ ;
        // }
    };

    using SFunctionLoadInfo=SFunctionCallInfo;


    TVector<uint8_t> ByteCode;
};